﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using LFSRecord2.Model;
using LFSRecord2.Events;
using System.Diagnostics;
using System.Windows.Media.Media3D;

namespace LFSRecord2.View.ViewportStructures
{
    /// <summary>
    /// Interaction logic for CompLayerRDViewObject.xaml
    /// </summary>
    public partial class CompLayerRDViewObject : Canvas
    {
        public static readonly DependencyProperty DoneUpdatingCurrentValuesProperty = DependencyProperty.Register(
            "DoneUpdatingCurrentValues",
            typeof(bool),
            typeof(CompLayerRDViewObject),
            new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDoneUpdatingCurrentValuesChanged))
        );
        public bool DoneUpdatingCurrentValues
        {
            get { return (bool)GetValue(DoneUpdatingCurrentValuesProperty); }
            set { SetValue(DoneUpdatingCurrentValuesProperty, value); }
        }
        private static void OnDoneUpdatingCurrentValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CompLayerRDViewObject compLayer = (CompLayerRDViewObject)d;
            CompLayerReplayData rdLayer = (CompLayerReplayData)compLayer.DataContext;
            bool mustRecreate = (rdLayer.HasParentLayer) ? true : false;

            if (mustRecreate == false && (rdLayer.UpdatedCurrentValues == 0 || compLayer.CurrentView == ViewportViews.ThreeD))
                return;

            //Debug.WriteLine("Updated properties (" + rdLayer.LayerName + ") : " + rdLayer.UpdatedCurrentValues);

            compLayer.redraw();
        }

        public static readonly DependencyProperty IsLayerSelectedProperty = DependencyProperty.Register(
            "IsLayerSelected",
            typeof(bool),
            typeof(CompLayerRDViewObject),
            new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsLayerSelectedChanged))
        );
        public bool IsLayerSelected
        {
            get { return (bool)GetValue(IsLayerSelectedProperty); }
            set { SetValue(IsLayerSelectedProperty, value); }
        }
        private static void OnIsLayerSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CompLayerRDViewObject compLayer = (CompLayerRDViewObject)d;
            compLayer.redraw();
        }

        public double Scale = 1;
        public ViewportViews CurrentView = ViewportViews.Top;

        public CompLayerRDViewObject()
        {
            InitializeComponent();

            Scale = LfsRecordController.ViewportScale;
            CurrentView = LfsRecordController.ViewportView;

            ServicesFactory.EventService.GetEvent<ViewportScaleChangedEvent>().Subscribe(ViewportScaleChangedHandler);
            ServicesFactory.EventService.GetEvent<ViewportViewChangedEvent>().Subscribe(ViewportViewChangedHandler);
        }

        private void CompLayerRDViewObject_Loaded(object sender, RoutedEventArgs e)
        {
            CompLayerReplayData rdLayer = (CompLayerReplayData)DataContext;
            rdLayer.Disposed += OnDataContextDispose;

            // Setup bindings
            Binding myBinding = new Binding("DoneUpdatingCurrentValues");
            myBinding.Source = rdLayer;
            SetBinding(CompLayerRDViewObject.DoneUpdatingCurrentValuesProperty, myBinding);

            myBinding = new Binding("IsSelected");
            myBinding.Source = rdLayer;
            SetBinding(CompLayerRDViewObject.IsLayerSelectedProperty, myBinding);

            //myBinding = new Binding("AnimationPath");
            //myBinding.Source = ((CompLayerPropertyPoint3D)nullLayer.Properties[(int)CompLayerNull.PropertyTypes.Position]);
            //PositionPath.SetBinding(Path.DataProperty, myBinding);

            //myBinding = new Binding("Point3DFrameCache");
            //myBinding.Source = (CompLayerPropertyPoint3D)rdLayer.Properties[(int)CompLayerNull.PropertyTypes.Position];
            //SetBinding(CompLayerRDViewObject.PositionPointCacheProperty, myBinding);

            redraw();
        }

        private void OnDataContextDispose(object sender, EventArgs e)
        {
            ServicesFactory.EventService.GetEvent<ViewportScaleChangedEvent>().Unsubscribe(ViewportScaleChangedHandler);
            ServicesFactory.EventService.GetEvent<ViewportViewChangedEvent>().Unsubscribe(ViewportViewChangedHandler);
        }

        private void ViewportScaleChangedHandler(double scale)
        {
            Scale = scale;

            CompLayerReplayData rdLayer = (CompLayerReplayData)DataContext;
            if (rdLayer.Properties.Count == 0)
            {
                Debug.WriteLine("Euhm, wanted to draw a rd layer with no properties?");
                return;
            }

            redraw();

            //DrawSubRectangles();
        }

        public void ViewportViewChangedHandler(ViewportViewChangedEventArgs e)
        {
            CurrentView = e.View;

            if (CurrentView != ViewportViews.ThreeD)
            {
                //Debug.WriteLine("Viewport view changed : " + e.View);
                redraw();
                //DrawSubRectangles();
            }
        }

        private void redraw()
        {
            CompLayerReplayData rdLayer = (CompLayerReplayData)DataContext;

            // Retrieve a transformed layer object (mesh)
            CompLayerMeshBase layerObjectMesh = rdLayer.CreateTransformedMesh(LfsRecordController.FrameIndex, new Vector3D(1 / Scale, 1 / Scale, 1 / Scale));

            // Draw the new MainObject geometry
            GeometryGroup tlrGroup = new GeometryGroup();
            LineGeometry lineGeom;
            for (int a = 0; a < layerObjectMesh.NumLineIndexes; a++)
            {
                lineGeom = new LineGeometry(
                    new Point(layerObjectMesh.Points[layerObjectMesh.LineIndexes[a]].X, layerObjectMesh.Points[layerObjectMesh.LineIndexes[a]].Y),
                    new Point(layerObjectMesh.Points[layerObjectMesh.LineIndexes[a + 1]].X, layerObjectMesh.Points[layerObjectMesh.LineIndexes[a + 1]].Y));
                lineGeom.Freeze();
                tlrGroup.Children.Add(lineGeom);

                a++;
            }

            // Add it to the drawer object
            GeometryDrawing gd = new GeometryDrawing();
            gd.Geometry = tlrGroup;
            gd.Pen = new Pen(Brushes.Blue, ((IsLayerSelected) ? 2 / Scale : 1 / Scale));
            //MainObjectBounds = gd.Bounds;

            // Apply it to the MainObject Image
            MainObject.Source = new DrawingImage(gd);
            MainObject.Stretch = Stretch.None;

            MainObject.RenderTransform = new TranslateTransform(
                gd.Bounds.Left,
                gd.Bounds.Top);

            // Position crosshair
            TransformGroup trGroup = new TransformGroup();
            trGroup.Children.Add(new ScaleTransform(1 / Scale, 1 / Scale));
            trGroup.Children.Add(new TranslateTransform(layerObjectMesh.CenterPoint.X, layerObjectMesh.CenterPoint.Y));
            PositionCrossHair.RenderTransform = trGroup;

            //if (rdLayer.HasParentLayer)
            //{
            //    DrawSubRectangles();
            //}
        }

        //private void DrawSubRectangles()
        //{
        //}

        private void Crosshair_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            CompLayerReplayData rdLayer = (CompLayerReplayData)DataContext;
            if (!rdLayer.IsSelected)
            {
                LfsRecordController.project.DeselectAll();
                rdLayer.IsSelected = true;
            }
        }

        private void Crosshair_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            CompLayerReplayData rdLayer = (CompLayerReplayData)DataContext;
        }
    }
}
